use crate::utils::strings::text_cut_all;

use super::{page::PageModel, Assets};

use chrono::{DateTime as CDateTime, Utc};
use serde::{Deserialize, Serialize};
use wither::{
    bson::doc,
    mongodb::bson::{oid::ObjectId, DateTime},
    Model,
};

mod serde_default {
    pub fn club_primary_color() -> String {
        "#FFFFFF".to_string()
    }
    pub fn club_outer_visible() -> bool {
        true
    }
    pub fn club_inner_visible() -> bool {
        true
    }
}

/// ## 社团标签
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClubTag {
    /// 标签名称
    pub name: String,
    /// 标签的颜色
    pub color: String,
    /// 标签描述
    pub description: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize, Model)]
#[model(index(keys = r#"doc!{"name_word":"text","introduction_word":"text"}"#))]
pub struct ClubModel {
    #[serde(rename = "_id", skip_serializing_if = "Option::is_none")]
    pub id: Option<ObjectId>,
    /// 社团名
    pub name: String,
    // 社团名，分词
    pub name_word: String,
    /// 社团介绍
    pub introduction: Option<String>,
    /// 社团简介，分词
    pub introduction_word: Option<String>,
    /// 社团位置(具体坐标，为地图显示预留)
    pub location: Option<String>,
    /// 社团地址(一段话描述社团在哪)
    pub address: Option<String>,
    /// 社团的主色调
    #[serde(default = "serde_default::club_primary_color")]
    pub primary_color: String,
    /// 游客是否可见
    #[serde(default = "serde_default::club_outer_visible")]
    pub outer_visible: bool,
    /// 用户是否可见
    #[serde(default = "serde_default::club_inner_visible")]
    pub inner_visible: bool,
    /// 社团图标
    pub favicon: Option<Assets>,
    /// 社团封面(可以是多张图)
    #[serde(default = "Vec::new")]
    pub cover_images: Vec<Assets>,
    /// 社团页面
    pub page: Option<PageModel>,
    /// 社团软删除
    pub valid: bool,
    /// 社团点击量
    #[serde(default = "Default::default")]
    pub watch_count: i64,
    #[serde(default = "Default::default")]
    pub daily_count: i64,
    /// 社团上次热度
    #[serde(default = "Default::default")]
    pub last_heat: f64,
    /// 社团当前热度
    #[serde(default = "Default::default")]
    pub heat: f64,
    /// 社团的标签集合
    #[serde(default = "Vec::new")]
    pub tags: Vec<ClubTag>,
    pub created_at: DateTime,
    pub updated_at: DateTime,
}
impl Default for ClubModel {
    fn default() -> Self {
        Self {
            id: None,
            name: "noname".to_string(),
            name_word: "noname".to_string(),
            introduction: None,
            introduction_word: None,
            location: None,
            address: None,
            cover_images: Vec::new(),
            page: None,
            primary_color: serde_default::club_primary_color(),
            outer_visible: serde_default::club_outer_visible(),
            inner_visible: serde_default::club_inner_visible(),
            favicon: None,
            valid: true,
            watch_count: 0,
            daily_count: 0,
            tags: Vec::new(),
            last_heat: 0.0,
            heat: 0.0,
            created_at: DateTime::now(),
            updated_at: DateTime::now(),
        }
    }
}
impl ClubModel {
    /// ## 更新分词
    pub fn update_word(&mut self) {
        self.name_word = text_cut_all(&self.name);
        if let Some(ref introduction) = self.introduction {
            self.introduction_word = Some(text_cut_all(introduction));
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClubModelDTO {
    pub id: Option<String>,
    pub name: String,
    pub introduction: Option<String>,
    pub location: Option<String>,
    pub address: Option<String>,
    #[serde(default = "serde_default::club_primary_color")]
    pub primary_color: String,
    #[serde(default = "serde_default::club_outer_visible")]
    pub outer_visible: bool,
    #[serde(default = "serde_default::club_inner_visible")]
    pub inner_visible: bool,
    pub favicon: Option<Assets>,
    #[serde(default = "Vec::new")]
    pub cover_images: Vec<Assets>,
    pub page: Option<PageModel>,
    pub tags: Vec<ClubTag>,
    /// 社团点击量
    pub watch_count: i64,
    pub daily_count: i64,
    pub heat: f64,
    pub created_at: CDateTime<Utc>,
    pub updated_at: CDateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SimpleClubModel {
    pub id: ObjectId,
    pub name: String,
    pub primary_color: String,
    pub favicon: Option<Assets>,
    pub cover_images: Vec<Assets>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SimpleClub {
    pub id: String,
    pub name: String,
    pub primary_color: String,
    pub favicon: Option<Assets>,
    pub cover_images: Vec<Assets>,
}

impl From<ClubModel> for SimpleClub {
    fn from(model: ClubModel) -> Self {
        Self {
            id: model
                .id
                .map(|oid| oid.to_string())
                .unwrap_or_else(|| "".into()),
            name: model.name,
            primary_color: model.primary_color,
            favicon: model.favicon,
            cover_images: model.cover_images,
        }
    }
}

impl From<SimpleClubModel> for SimpleClub {
    fn from(model: SimpleClubModel) -> Self {
        Self {
            id: model.id.to_string(),
            name: model.name,
            primary_color: model.primary_color,
            favicon: model.favicon,
            cover_images: model.cover_images,
        }
    }
}

impl From<ClubModel> for SimpleClubModel {
    fn from(model: ClubModel) -> Self {
        Self {
            id: model.id.unwrap_or_default(),
            name: model.name,
            primary_color: model.primary_color,
            favicon: model.favicon,
            cover_images: model.cover_images,
        }
    }
}

impl From<ClubModel> for ClubModelDTO {
    fn from(club: ClubModel) -> Self {
        Self {
            id: club.id.map(|v| v.to_string()),
            name: club.name,
            introduction: club.introduction,
            location: club.location,
            address: club.address,
            primary_color: club.primary_color,
            outer_visible: club.outer_visible,
            inner_visible: club.inner_visible,
            favicon: club.favicon,
            cover_images: club.cover_images,
            page: club.page,
            tags: club.tags,
            watch_count: club.watch_count,
            daily_count: club.daily_count,
            heat: club.heat,
            created_at: club.created_at.to_chrono(),
            updated_at: club.updated_at.to_chrono(),
        }
    }
}
